package com.tyk.bookstore.front.member.service.impl;


import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tyk.bookstore.front.common.core.util.AssertUtil;
import com.tyk.bookstore.front.common.core.util.IdGenerator;
import com.tyk.bookstore.front.member.constant.MemberConstant;
import com.tyk.bookstore.front.member.model.entity.DeliveryAddressDo;
import com.tyk.bookstore.front.member.model.query.DeliveryAddressAddQuery;
import com.tyk.bookstore.front.member.model.query.DeliveryAddressUpdateQuery;
import com.tyk.bookstore.front.member.model.result.DeliveryAddressResultEnum;
import com.tyk.bookstore.front.member.model.vo.DeliveryAddressVo;
import com.tyk.bookstore.front.member.repository.DeliveryAddressRepository;
import com.tyk.bookstore.front.member.service.DeliveryAddressService;
import com.tyk.bookstore.front.member.util.MapStructMember;
import com.tyk.bookstore.front.system.model.dto.AreaFullLevelDto;
import com.tyk.bookstore.front.system.service.AreaApiService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author tyk
 * @description 收获地址管理
 */
@Service
@RequiredArgsConstructor
public class DeliveryAddressServiceImp implements DeliveryAddressService {

    private final DeliveryAddressRepository deliveryAddressRepository;
    private final AreaApiService areaApiService;
    private final MapStructMember mapStructMember;

    @Override
    public DeliveryAddressVo getById(Long id) {
        Long memberId = StpUtil.getLoginIdAsLong();

        AssertUtil.isTrue(
                deliveryAddressRepository.exist2Eq(
                        DeliveryAddressDo::getId,id,
                        DeliveryAddressDo::getMemberId,memberId,
                        DeliveryAddressDo.class
                ),
                DeliveryAddressResultEnum.ADDRESS_NOT_FOUND
        );
        DeliveryAddressDo dad = deliveryAddressRepository.selectById(id);
        DeliveryAddressVo dav = mapStructMember.toDeliveryAddressVo(dad);

        AreaFullLevelDto afd = areaApiService
                .getAreaFullLevelDtoList(Set.of(dav.getAreaCode()))
                .get(0);
        dav.setAreaFullName(afd.getFullName())
                .setAreaCodeList(afd.getCodeList());

        return dav;
    }

    @Override
    public List<DeliveryAddressVo> getList() {

        Long memberId = StpUtil.getLoginIdAsLong();

        // 地址
        LambdaQueryWrapper<DeliveryAddressDo> w = Wrappers.lambdaQuery();
        w.eq(DeliveryAddressDo::getMemberId, memberId);
        List<DeliveryAddressVo> voList = mapStructMember.toDeliveryAddressVoList(
                deliveryAddressRepository.selectList(w)
        );

        // 区域信息
        Map<Long, AreaFullLevelDto> map = areaApiService
                .getAreaFullLevelDtoList(
                        voList.stream().map(DeliveryAddressVo::getAreaCode).collect(Collectors.toSet())
                ).stream().collect(Collectors.toMap(AreaFullLevelDto::getCode, it -> it));
        voList.forEach(it -> {
            AreaFullLevelDto dto = map.get(it.getAreaCode());
            it.setAreaFullName(dto.getFullName());
            it.setAreaCodeList(dto.getCodeList());
        });

        return voList;
    }

    @Override
    public void add(DeliveryAddressAddQuery query) {
        Long memberId = StpUtil.getLoginIdAsLong();
        // 校验地址数量
        Long addressNum = deliveryAddressRepository.count1Eq0Limit(
                DeliveryAddressDo::getMemberId, memberId,
                MemberConstant.ADDRESS_MAX_NUM,
                DeliveryAddressDo.class
        );
        AssertUtil.lt(addressNum.intValue(), MemberConstant.ADDRESS_MAX_NUM, DeliveryAddressResultEnum.ADDRESS_NUM_EXCEED_LIMIT);
        // 校验区域
        areaApiService.assertLowestArea(query.getAreaCode());
        // 添加到数据库
        DeliveryAddressDo deliveryAddress = mapStructMember.toDeliveryAddressDo(query);
        deliveryAddress.setId(IdGenerator.id()).setMemberId(memberId);
        deliveryAddressRepository.insert(deliveryAddress);
    }

    @Override
    public void updateById(DeliveryAddressUpdateQuery query) {
        deliveryAddressRepository.updateById(
                mapStructMember.toDeliveryAddressDo(query)
        );
    }

    @Override
    public void deleteById(Long id) {
        Long memberId = StpUtil.getLoginIdAsLong();
        // 检查收货地址是否存在
        AssertUtil.isTrue(
                deliveryAddressRepository.exist2Eq(
                        DeliveryAddressDo::getId, id,
                        DeliveryAddressDo::getMemberId, memberId,
                        DeliveryAddressDo.class
                ),
                DeliveryAddressResultEnum.ADDRESS_NOT_FOUND
        );
        // 删除
        deliveryAddressRepository.delete2Eq(
                DeliveryAddressDo::getId,id,
                DeliveryAddressDo::getMemberId,memberId,
                DeliveryAddressDo.class
        );
    }

    @Override
    public void setDefault(Long id) {
        long memberId = StpUtil.getLoginIdAsLong();
        // 检查收货地址是否存在
        AssertUtil.isTrue(
                deliveryAddressRepository.exist2Eq(
                        DeliveryAddressDo::getId, id,
                        DeliveryAddressDo::getMemberId, memberId,
                        DeliveryAddressDo.class
                ),
                DeliveryAddressResultEnum.ADDRESS_NOT_FOUND
        );
        // 将现默认收货地址的默认标志置为false
        deliveryAddressRepository.update1Set2Eq(
                DeliveryAddressDo::getDefaulted, false,
                DeliveryAddressDo::getMemberId, memberId,
                DeliveryAddressDo::getDefaulted, true,
                DeliveryAddressDo.class
        );
        // 设置新的默认收货地址
        deliveryAddressRepository.update1Set2Eq(
                DeliveryAddressDo::getDefaulted, true,
                DeliveryAddressDo::getId, id,
                DeliveryAddressDo::getMemberId, memberId,
                DeliveryAddressDo.class
        );
    }

}
